Aprende a crear potentes endpoints de API usando los Route Handlers de Next.js. Esta gu铆a cubre todo, desde la configuraci贸n b谩sica hasta t茅cnicas avanzadas, con ejemplos pr谩cticos y mejores pr谩cticas.
Route Handlers de Next.js: Una Gu铆a Completa para la Creaci贸n de Endpoints de API
Next.js ha revolucionado la forma en que construimos aplicaciones web con sus potentes caracter铆sticas como el renderizado del lado del servidor, la generaci贸n de sitios est谩ticos y, ahora, los Route Handlers. Los Route Handlers proporcionan una forma flexible y eficiente de crear endpoints de API directamente dentro de tu aplicaci贸n Next.js. Esta gu铆a explora el concepto de los Route Handlers, sus beneficios y c贸mo usarlos eficazmente para construir APIs robustas.
驴Qu茅 son los Route Handlers de Next.js?
Los Route Handlers son funciones definidas dentro del directorio app de un proyecto Next.js que manejan las solicitudes HTTP entrantes. A diferencia del antiguo enfoque pages/api (que utiliza Rutas de API), los Route Handlers ofrecen una manera m谩s optimizada y flexible de definir endpoints de API junto a tus componentes de React. Son esencialmente funciones sin servidor ejecutadas en el borde o en el entorno de servidor que elijas.
Piensa en los Route Handlers como la l贸gica del backend de tu aplicaci贸n Next.js, responsables de procesar solicitudes, interactuar con bases de datos y devolver respuestas.
Beneficios de Usar Route Handlers
- Colocaci贸n: Los Route Handlers residen directamente junto a tus componentes de React dentro del directorio
app, promoviendo una mejor organizaci贸n y mantenibilidad del c贸digo. - Soporte para TypeScript: El soporte integrado para TypeScript garantiza la seguridad de tipos y una mejor experiencia para el desarrollador.
- Integraci贸n de Middleware: Integra f谩cilmente middleware para tareas como autenticaci贸n, autorizaci贸n y validaci贸n de solicitudes.
- Soporte para Streaming: Los Route Handlers pueden transmitir datos, permiti茅ndote enviar respuestas de forma incremental, lo cual es beneficioso para grandes conjuntos de datos o procesos de larga duraci贸n.
- Edge Functions: Despliega los Route Handlers como Edge Functions para obtener respuestas de baja latencia m谩s cerca de tus usuarios, aprovechando las CDNs globales.
- Dise帽o de API Simplificado: Los Route Handlers proporcionan una API limpia e intuitiva para manejar solicitudes y respuestas.
- Integraci贸n con Server Actions: La estrecha integraci贸n con las Server Actions permite una comunicaci贸n fluida entre tus componentes del lado del cliente y la l贸gica del lado del servidor.
Configurando tu Proyecto de Next.js
Antes de sumergirte en los Route Handlers, aseg煤rate de tener un proyecto de Next.js configurado con el directorio app. Si est谩s comenzando un nuevo proyecto, usa el siguiente comando:
npx create-next-app@latest my-nextjs-app
Elige el directorio app durante el proceso de configuraci贸n para habilitar el nuevo sistema de enrutamiento.
Creando tu Primer Route Handler
Vamos a crear un endpoint de API simple que devuelva una respuesta JSON. Crea un nuevo directorio dentro del directorio app, por ejemplo, /app/api/hello. Dentro de este directorio, crea un archivo llamado route.ts (o route.js si no est谩s usando TypeScript).
Aqu铆 est谩 el c贸digo para tu primer Route Handler:
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });
}
Explicaci贸n:
import { NextResponse } from 'next/server';: Importa el objetoNextResponse, que se utiliza para construir respuestas de API.export async function GET(request: Request) { ... }: Define una funci贸n as铆ncrona que maneja las solicitudes GET al endpoint/api/hello. El par谩metrorequestproporciona acceso al objeto de la solicitud entrante.return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });: Crea una respuesta JSON con un mensaje y la devuelve usandoNextResponse.json().
Ahora, puedes acceder a este endpoint navegando a /api/hello en tu navegador o usando una herramienta como curl o Postman.
Manejando Diferentes M茅todos HTTP
Los Route Handlers soportan varios m茅todos HTTP como GET, POST, PUT, DELETE, PATCH y OPTIONS. Puedes definir funciones separadas para cada m茅todo dentro del mismo archivo route.ts.
// app/api/users/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// L贸gica para recuperar todos los usuarios de la base de datos
const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // Datos de ejemplo
return NextResponse.json(users);
}
export async function POST(request: Request) {
const data = await request.json(); // Analiza el cuerpo de la solicitud como JSON
// L贸gica para crear un nuevo usuario en la base de datos usando 'data'
const newUser = { id: 3, name: data.name, email: data.email }; // Ejemplo
return NextResponse.json(newUser, { status: 201 }); // Devuelve el nuevo usuario con un c贸digo de estado 201 Created
}
Explicaci贸n:
- La funci贸n
GETrecupera una lista de usuarios (simulada aqu铆) y la devuelve como una respuesta JSON. - La funci贸n
POSTanaliza el cuerpo de la solicitud como JSON, crea un nuevo usuario (simulado) y devuelve el nuevo usuario con un c贸digo de estado 201 Created.
Accediendo a los Datos de la Solicitud
El objeto request proporciona acceso a diversa informaci贸n sobre la solicitud entrante, incluyendo encabezados, par谩metros de consulta y el cuerpo de la solicitud.
Encabezados
Puedes acceder a los encabezados de la solicitud usando la propiedad request.headers:
export async function GET(request: Request) {
const userAgent = request.headers.get('user-agent');
console.log('User Agent:', userAgent);
return NextResponse.json({ userAgent });
}
Par谩metros de Consulta
Para acceder a los par谩metros de consulta, puedes usar el constructor URL:
export async function GET(request: Request) {
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);
const id = searchParams.get('id');
console.log('ID:', id);
return NextResponse.json({ id });
}
Cuerpo de la Solicitud
Para solicitudes POST, PUT y PATCH, puedes acceder al cuerpo de la solicitud usando los m茅todos request.json() o request.text(), dependiendo del tipo de contenido.
export async function POST(request: Request) {
const data = await request.json();
console.log('Data:', data);
return NextResponse.json({ receivedData: data });
}
Devolviendo Respuestas
El objeto NextResponse se utiliza para construir respuestas de API. Proporciona varios m茅todos para establecer encabezados, c贸digos de estado y cuerpos de respuesta.
Respuestas JSON
Usa el m茅todo NextResponse.json() para devolver respuestas JSON:
return NextResponse.json({ message: 'Success!', data: { name: 'John Doe' } }, { status: 200 });
Respuestas de Texto
Usa el constructor new Response() para devolver respuestas de texto plano:
return new Response('Hello, world!', { status: 200, headers: { 'Content-Type': 'text/plain' } });
Redirecciones
Usa NextResponse.redirect() para redirigir a los usuarios a una URL diferente:
import { redirect } from 'next/navigation';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.redirect(new URL('/new-location', request.url));
}
Estableciendo Encabezados
Puedes establecer encabezados personalizados usando la opci贸n headers en NextResponse.json() o new Response():
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });
Integraci贸n de Middleware
El middleware te permite ejecutar c贸digo antes de que una solicitud sea manejada por tu Route Handler. Esto es 煤til para la autenticaci贸n, autorizaci贸n, registro y otras preocupaciones transversales.
Para crear un middleware, crea un archivo llamado middleware.ts (o middleware.js) en el directorio app o en cualquier subdirectorio. El middleware se aplicar谩 a todas las rutas dentro de ese directorio y sus subdirectorios.
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/protected/:path*'], // Aplica este middleware a rutas que comiencen con /protected/
};
Explicaci贸n:
- La funci贸n
middlewareverifica la existencia de un token de autenticaci贸n en las cookies de la solicitud. - Si falta el token, redirige al usuario a la p谩gina de inicio de sesi贸n.
- De lo contrario, permite que la solicitud contin煤e hacia el Route Handler.
- El objeto
configespecifica que este middleware solo debe aplicarse a las rutas que comiencen con/protected/.
Manejo de Errores
El manejo adecuado de errores es crucial para construir APIs robustas. Puedes usar bloques try...catch para manejar excepciones y devolver respuestas de error apropiadas.
export async function GET(request: Request) {
try {
// Simula un error
throw new Error('Something went wrong!');
} catch (error: any) {
console.error('Error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Explicaci贸n:
- El bloque
try...catchcaptura cualquier excepci贸n que ocurra dentro del Route Handler. - En el bloque
catch, el error se registra en la consola y se devuelve una respuesta de error con un c贸digo de estado 500 Internal Server Error.
Respuestas en Streaming
Los Route Handlers soportan respuestas en streaming, lo que te permite enviar datos de forma incremental al cliente. Esto es particularmente 煤til para grandes conjuntos de datos o procesos de larga duraci贸n.
import { Readable } from 'stream';
import { NextResponse } from 'next/server';
async function* generateData() {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // Simula un retraso
yield `Data chunk ${i}\n`;
}
}
export async function GET(request: Request) {
const readableStream = Readable.from(generateData());
return new Response(readableStream, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
Explicaci贸n:
- La funci贸n
generateDataes un generador as铆ncrono que produce fragmentos de datos con un retraso. - El m茅todo
Readable.from()crea un stream legible a partir del generador. - El objeto
Responsese crea con el stream legible como cuerpo, y el encabezadoContent-Typese establece entext/plain.
Autenticaci贸n y Autorizaci贸n
Asegurar tus endpoints de API es crucial. Puedes implementar la autenticaci贸n y la autorizaci贸n usando middleware o directamente dentro de tus Route Handlers.
Autenticaci贸n
La autenticaci贸n verifica la identidad del usuario que realiza la solicitud. Los m茅todos de autenticaci贸n comunes incluyen:
- JWT (JSON Web Tokens): Genera un token tras un inicio de sesi贸n exitoso y verif铆calo en solicitudes posteriores.
- Autenticaci贸n basada en sesi贸n: Usa cookies para almacenar identificadores de sesi贸n y verificarlos en cada solicitud.
- OAuth: Delega la autenticaci贸n a un proveedor de terceros como Google o Facebook.
Aqu铆 hay un ejemplo de autenticaci贸n JWT usando middleware:
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import jwt from 'jsonwebtoken';
const secret = process.env.JWT_SECRET || 'your-secret-key'; // Reemplaza con un secreto fuerte y generado aleatoriamente
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
return NextResponse.json({ message: 'Authentication required' }, { status: 401 });
}
try {
jwt.verify(token, secret);
return NextResponse.next();
} catch (error) {
return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
}
}
export const config = {
matcher: ['/api/protected/:path*'],
};
Autorizaci贸n
La autorizaci贸n determina a qu茅 recursos puede acceder un usuario. Esto generalmente se basa en roles o permisos.
Puedes implementar la autorizaci贸n dentro de tus Route Handlers verificando los roles o permisos del usuario y devolviendo un error si no tienen acceso.
// app/api/admin/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Asume que tienes una funci贸n para obtener el rol del usuario desde el token o la sesi贸n
const userRole = await getUserRole(request);
if (userRole !== 'admin') {
return NextResponse.json({ message: 'Unauthorized' }, { status: 403 });
}
// L贸gica para recuperar datos de administrador
const adminData = { message: 'Admin data' };
return NextResponse.json(adminData);
}
async function getUserRole(request: Request): Promise {
// Reemplaza con tu l贸gica real para extraer el rol del usuario de la solicitud
// Esto podr铆a implicar verificar un token JWT o una sesi贸n
return 'admin'; // Ejemplo: rol hardcodeado para la demostraci贸n
}
Desplegando Route Handlers
Los Route Handlers se despliegan como funciones sin servidor en tu proveedor de hosting elegido. Next.js soporta varias plataformas de despliegue, incluyendo Vercel, Netlify, AWS y m谩s.
Para Vercel, el despliegue es tan simple como conectar tu repositorio de Git a Vercel y subir tu c贸digo. Vercel detecta autom谩ticamente tu proyecto de Next.js y despliega tus Route Handlers como funciones sin servidor.
T茅cnicas Avanzadas
Edge Functions
Los Route Handlers se pueden desplegar como Edge Functions, que se ejecutan en el borde de una CDN, m谩s cerca de tus usuarios. Esto puede reducir significativamente la latencia y mejorar el rendimiento.
Para desplegar un Route Handler como una Edge Function, a帽ade el runtime edge a tu archivo route.ts:
export const runtime = 'edge';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Hello from the Edge!' });
}
Server Actions
Las Server Actions te permiten ejecutar c贸digo del lado del servidor directamente desde tus componentes de React. Los Route Handlers y las Server Actions funcionan juntos sin problemas, permiti茅ndote construir aplicaciones complejas con facilidad.
Aqu铆 hay un ejemplo de c贸mo usar una Server Action para llamar a un Route Handler:
// app/components/MyComponent.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
async function handleSubmit(data: FormData) {
'use server';
const name = data.get('name');
const email = data.get('email');
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name, email }),
});
if (response.ok) {
router.refresh(); // Refresca la p谩gina para reflejar los cambios
}
}
export default function MyComponent() {
const router = useRouter();
return (
);
}
Almacenamiento en Cach茅
El almacenamiento en cach茅 puede mejorar significativamente el rendimiento de tus endpoints de API. Puedes usar el encabezado Cache-Control para controlar c贸mo tus respuestas son almacenadas en cach茅 por los navegadores y las CDNs.
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });
Este ejemplo establece el encabezado Cache-Control en public, max-age=3600, lo que indica a los navegadores y CDNs que almacenen en cach茅 la respuesta durante una hora.
Mejores Pr谩cticas
- Usa TypeScript: Aprovecha la seguridad de tipos de TypeScript para mejorar la calidad del c贸digo y prevenir errores.
- Valida las Solicitudes: Valida las solicitudes entrantes para garantizar la integridad de los datos y prevenir entradas maliciosas.
- Maneja Errores con Gracia: Implementa un manejo de errores adecuado para proporcionar mensajes de error informativos a los clientes.
- Asegura tus Endpoints: Implementa autenticaci贸n y autorizaci贸n para proteger tus endpoints de API.
- Usa Middleware: Usa middleware para preocupaciones transversales como autenticaci贸n, registro y validaci贸n de solicitudes.
- Almacena Respuestas en Cach茅: Usa el almacenamiento en cach茅 para mejorar el rendimiento de tus endpoints de API.
- Monitorea tus APIs: Monitorea tus APIs para identificar y resolver problemas r谩pidamente.
- Documenta tus APIs: Documenta tus APIs para que sean f谩ciles de usar para otros desarrolladores. Considera usar herramientas como Swagger/OpenAPI para la documentaci贸n de la API.
Ejemplos del Mundo Real
Aqu铆 hay algunos ejemplos del mundo real de c贸mo se pueden usar los Route Handlers:
- API de comercio electr贸nico: Crea endpoints de API para gestionar productos, pedidos y usuarios.
- API de redes sociales: Crea endpoints de API para publicar tweets, seguir a usuarios y recuperar l铆neas de tiempo.
- API de Sistema de Gesti贸n de Contenidos (CMS): Crea endpoints de API para gestionar contenido, usuarios y configuraciones.
- API de an谩lisis de datos: Crea endpoints de API para recopilar y analizar datos. Por ejemplo, un Route Handler podr铆a recibir datos de p铆xeles de seguimiento en diferentes sitios web y agregar la informaci贸n para la elaboraci贸n de informes.
Ejemplo de comercio electr贸nico internacional: Un Route Handler utilizado para recuperar los precios de los productos seg煤n el pa铆s del usuario. El endpoint podr铆a usar la geolocalizaci贸n de la solicitud (derivada de la direcci贸n IP) para determinar la ubicaci贸n del usuario y devolver los precios en la moneda apropiada. Esto contribuye a una experiencia de compra localizada.
Ejemplo de autenticaci贸n global: Un Route Handler que implementa la autenticaci贸n multifactor (MFA) para usuarios de todo el mundo. Esto podr铆a implicar el env铆o de c贸digos SMS o el uso de aplicaciones de autenticaci贸n, respetando al mismo tiempo las regulaciones de privacidad y las infraestructuras de telecomunicaciones de las diferentes regiones.
Entrega de contenido multiling眉e: Un Route Handler que entrega contenido en el idioma preferido del usuario. Esto se puede determinar a partir del encabezado `Accept-Language` en la solicitud. Este ejemplo resalta la necesidad de una codificaci贸n UTF-8 adecuada y soporte para idiomas de derecha a izquierda cuando sea apropiado.
Conclusi贸n
Los Route Handlers de Next.js proporcionan una forma potente y flexible de crear endpoints de API directamente dentro de tu aplicaci贸n Next.js. Al aprovechar los Route Handlers, puedes construir APIs robustas con facilidad, colocar tu l贸gica de backend junto a tus componentes de React y aprovechar caracter铆sticas como middleware, streaming y Edge Functions.
Esta gu铆a completa ha cubierto todo, desde la configuraci贸n b谩sica hasta las t茅cnicas avanzadas. Siguiendo las mejores pr谩cticas descritas en esta gu铆a, puedes construir APIs de alta calidad que sean seguras, de alto rendimiento y f谩ciles de mantener.